<?php
/**
 * socket 服务端 YiChao
 * Class SocketServer
 */
ini_set('memory_limit', '1048M');
include_once __DIR__ . '/../BaseShell.php';
date_default_timezone_set('Asia/Chongqing');
$env = getenv('RUNTIME_ENVIROMENT') ? getenv('RUNTIME_ENVIROMENT') : (defined('SHELL_VARIABLE') ? SHELL_VARIABLE : '');
$env = empty($env) ? 'rls' : $env;
$config = require_once LIBRARY_DIR . '/Conf/' . $env . '/swoole.php';
if(!isset($config['socket'])){
    echo 'config no find'.PHP_EOL;
    return false;
}
$server = new Swoole\WebSocket\Server($config['socket']['host'], $config['socket']['port']);
$server->set($config['socket']['set']);
//客户端链接
$server->on('open', function (Swoole\WebSocket\Server $server, $request) {
    $request_uri = $request->server['request_uri'];
    $workerId = substr($request_uri,strripos($request_uri,"/")+1);
    try {
        //接受参数
        if(empty($workerId)){
            Func_Log::write('call_socket','OPEN WARING EMPTY WORKERID',"REQUEST：".$request->server['request_uri']);
            $server->push($request->fd, json_encode(['execute'=>'online','result'=>400,'message'=>'链接失败，缺少必要参数']));
            $server->close($request->fd);
        }
        //存储链接信息
        $history_fd =Lib_Redis_String::get('SOCKET_WORKERID_'.$workerId);
        if($history_fd && $server->isEstablished($history_fd)){
            $server->push($history_fd, json_encode(['execute'=>'forced_0ffline','result'=>301,'error'=>'打开其他页面，该页面链接掉线，可刷新重新链接']));
        }
        $set_res = Lib_Redis_String::set('SOCKET_WORKERID_'.$workerId,$request->fd);
        if(!$set_res){
            Func_Log::write('call_socket','OPEN WARING SAVE FD ERROR',"WORKERID：{$workerId} FD ：{$request->fd}");
            $server->push($request->fd, json_encode(['execute'=>'online','result'=>401,'error'=>'存储链接信息失败']));
            $server->close($request->fd);
        }
        Func_Log::write('call_socket','OPEN SUCCESS',"WORKERID：{$workerId} FD：{$request->fd}");
        //获取坐席状态
        $line = $workerId > 7000 ? 1 : 2;
        $res = Module_CallCenter_YunKeFu_Call::getInstance($line)->queryUserState(
            [
                'workerId'=>$workerId,
            ]
        );
        $status = 2;
        if(!empty($res['code']) && $res['code'] == 200 && $res['data']['flag'] =='reserve'){
            $status = 1;
        }
        $server->push($request->fd, json_encode(['execute' => 'online', 'result' => 200, 'status' =>$status]));
    }catch (Exception $e) {//捕获异常
        Func_Log::write('call_socket','OPEN CATCH ERROR',"WORKERID：{$workerId} FD：{$request->fd} CALLTYPE：online" ." ERROR：".json_encode($e));
        $server->push($request->fd, json_encode(['execute'=>'online','result'=>500,'error'=>'服务器异常']));
        $server->close($request->fd);
    }

});
//接受http请求
$server->on('request', function($request,  $response) {
    global $server;//调用外部sever
    $param = empty($request->get) ? $request->post : $request->get;
    switch ($param['CallState']) {
        case 'Ringing':
        case 'Ring':
            $execute = 'bell';
            break;
        case 'Link':
            $execute = 'connect';
            break;
        case 'Hangup':
        case 'Unlink':
            $execute = 'hangup';
            break;
        default:
            Func_Log::write('call_socket','PUSH WARING PARAM ERROR',"REQUEST：".json_encode($param));
            $response->end();
            return false;
    }
    //工号
    if(empty($param['Agent'])){
        Func_Log::write('call_socket','PUSH WARING WORKERID EMPTY'," MODEL：{$execute}  REQUEST：".json_encode($param));
        $response->end();
        return false;
    }
    $workerId = $param['Agent'];
    //呼叫类型
    if(empty($param['CallType'])){
        Func_Log::write('call_socket','PUSH WARING CallType EMPTY',"MODEL：{$execute}  REQUEST：".json_encode($param));
        $response->end();
        return false;
    }
    $type = in_array($param['CallType'] ,[ 'dialout','dialTransfer']) ? 'callOut' : 'callIn';
    if($execute == 'hangup'){
        Lib_Redis_String::setex($param['CallSheetID'],1800,json_encode(['mainUniqueId'=>$param['CallSheetID'],'hangup_type'=>$type,'down_time'=>time()+60,'push_data'=>$param]));
        Lib_Redis_List::rPush('YunKeFu_CALL_TICKET',json_encode(['mainUniqueId'=>$param['CallSheetID'],'hangup_type'=>$type,'down_time'=>time()+60,'push_data'=>$param]));

        if($param['ActionID']){
            $case_id = explode("_",$param['ActionID'])[0];
            if($case_id){
                Lib_Redis_Hash::hset($case_id,$param['CallSheetID'],$param['ActionID']);
                Lib_Redis_Hash::expire($case_id,1800);
            }
        }

    }
    if($type == 'callOut' && in_array($param['CallState'],['Hangup','Unlink'])){
        $mobile = Lib_Redis_String::get($workerId."_fl");
        if($mobile){
            Func_Log::write('call_socket', 'unbind', "WORKERID：{$workerId} CALLTYPE：{$type} MODEL：{$execute}  Mobile：" . $mobile);
            Lib_Repair_Main::unBindTel([
                'telX'=>$mobile
            ]);
        }
    }

    $fd = Lib_Redis_String::get('SOCKET_WORKERID_'.$workerId);
    if(!$fd) {
        Func_Log::write('call_socket', 'PUSH WARING WORKERID NOT ONLINE', "WORKERID：{$workerId} FD：{$fd} CALLTYPE：{$type} MODEL：{$execute}  REQUEST：" . json_encode($param));
        $response->end();
        return false;
    }
    switch ($type) {
        case 'callOut':
            if($server->isEstablished($fd)){
                $server->push($fd, json_encode(['callType' => "callOut_push",'execute'=> $type.'_'.$execute,'callId' => $param['CallSheetID'],'phone' => $param['CalledNo']]));
            }else{
                Func_Log::write('call_socket','PUSH WARING FD NOT ONLINE',"WORKERID：{$workerId} FD：{$fd} CALLTYPE：{$type} MODEL：{$execute}  REQUEST：".json_encode($param));
            }
            break;
        case 'callIn':
            $callInType = 2;
            $search = $param['CallNo'];
            if(!empty($param['IVRKEY'])){
                $ivrkey = explode('-',$param['IVRKEY']);
                $callInType = explode('@',$ivrkey[0])[1];
            }
            if($callInType == 1 ){
                $idcard =  Lib_Redis_String::get($param['CallNo']);
                if($idcard){
                    $search = $idcard;
                    if(strlen($search) == 17){
                        $search = $search."X";
                    }
                }
            }else{
                Lib_Redis_String::setex($param['CallSheetID']."_suggestion",3600,$callInType);
            }
            if($server->isEstablished($fd)){
                $server->push($fd, json_encode(['callType' => "callIn_push",'execute'=> $type.'_'.$execute,'callId' => $param['CallSheetID'],'phone' => $param['CallNo'],'callInType'=>$callInType,'search'=>$search]));
            }else{
                for($i=0;$i<=10;$i++){
                    $fd = Lib_Redis_String::get('SOCKET_WORKERID_'.$workerId);
                    sleep(1);
                    if($server->isEstablished($fd)) {
                        $server->push($fd, json_encode(['callType' => "callIn_push",'execute'=> $type.'_'.$execute,'callId' => $param['uniqueid'],'phone' => $param['CallNo']]));
                        break;
                    }else{
                        Func_Log::write('call_socket','PUSH WARING FD NOT ONLINE',"WORKERID：{$workerId} FD：{$fd} CALLTYPE：{$type} MODEL：{$execute}  REQUEST：".json_encode($param));
                    }
                }
            }
    }
    Func_Log::write('call_socket','PUSH SUCCESS',"WORKERID：{$workerId} FD：{$fd} CALLTYPE：{$type} MODEL：{$execute}  REQUEST：".json_encode($param));
    $response->end();
    return true;

});
//接受client请求
$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
    if($frame->data == "Hello"){
        $server->push($frame->fd, "Hi");
        return true;
    }
    $param = json_decode($frame->data,true);
    $param['pass'] = "YunKeFu";
    $callType  = $param['callType'];
    if(empty($param['execute']) || empty($param['workerId'])){
        Func_Log::write('call_socket','MESSAGE WARING PARAM ERROR'," REQUEST：".json_encode($param));
        $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>'call','result'=>402,'error'=>'缺少必要参数']));
        return false;
    }
    try {
        if($param['execute'] == 'callOut'){
            if(in_array($param['toTel'],Module_Mediate_CaseLitigant::$prohibitMobile)){
                $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>$param['execute'],'result'=>402,'error'=>'黑名单号码，禁止外呼']));
                return false;
            }
            $businessData = explode('-',$param['businessData']);
            $isFlashsms = $businessData[0];
            $outNumber = empty($businessData[1]) ? '' : $businessData[1];
            $h = date("H");
            if($h < 8 || $h > 20){
                $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>'callOut','result'=>403,'error'=>'呼叫时间为早8点到晚8点']));
                return false;
            }
            $case_id = empty($param['caseId']) ? 0 : $param['caseId'];
            $uniquid = $case_id."_".uniqid();
            unset($param['caseId']);
            if(empty($param['mobileType']) || empty($param['mobileId'])){
                $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>$param['execute'],'result'=>402,'error'=>'缺少必要参数']));
                return false;
            }
            if(empty($outNumber)){
                $outNumber = Lib_Redis_Hash::hGet('WORK_OUT_NUM',$param['workerId']);
                if($outNumber){
                    $param['OutShow'] = $outNumber;
                }else{
                    $worker = Module_Mediate_Workernumber::getInstance()->getOne([],["workerId={$param['workerId']}","isDel=1"]);
                    if(empty($worker['outNumber'])){
                        $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>'call','result'=>403,'error'=>'当前坐席未配置外显号码，请联系系统管理员配置']));
                        return false;
                    }
                    $param['OutShow'] = $outNumber = $worker['outNumber'];
                    Lib_Redis_Hash::hset('WORK_OUT_NUM',$param['workerId'],$worker['outNumber']);
                }
            }else{
                $param['OutShow'] = $outNumber;
            }
            if(isset(Module_Mediate_Workernumber::$change[$param['OutShow']])){
                $param['OutShow'] = Module_Mediate_Workernumber::$change[$param['OutShow']];
            }
            //如果是修复号码，需要去运营商绑定中间号
            if(in_array($param['mobileType'],[2,3])){
                $repairData = Module_Repair_RepairResult::getInstance()->getItemById($param['mobileId'],true);
                if(empty($repairData)){
                    $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>$param['execute'],'result'=>402,'error'=>'未查询到修复数据']));
                    return false;
                }
                $repairData['seatNumber'] = $param['OutShow'];
                $repairData['showNumber'] = $outNumber ;
                $res = Lib_Repair_Main::bindTel([
                    'pass'=> $repairData['repairType'] == 1 ? "YiDong" : "LianTong",
                    'data'=>$repairData
                ]);
                $uniquid = $param['mobileType'] == 3 ? 'LT'.$uniquid : $uniquid;
                if($res['code'] != 200){
                    Func_Log::write('call_socket', 'submit ISP error', 'mobileId = '.$param['mobileId'].' res= ' . json_encode($res));
                    $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>$param['execute'],'result'=>402,'error'=>$res['message']]));
                    return false;
                }
                $param['toTel'] = $res['data']['toTel'];
                Lib_Redis_String::setex($param['workerId']."_fl",1800,$param['toTel']);
            }else{//非修复号码判断拨打次数
                if(!in_array($param['toTel'],['17310698030'])){
                    $call_num = Lib_Redis_String::get("CALLNUM-".$param['toTel']);
                    if($call_num){
                        if($call_num >= 3){
                            $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>'callOut','result'=>403,'error'=>'拨打次数超限（3次/天）']));
                            return false;
                        }
                    }
                }

            }
            $param['ActionID'] = $uniquid;
            Lib_Redis_String::setex("CALL-CASEID" .$uniquid, 1800, $case_id);
            Lib_Redis_String::setex("CALL-MOBILETYPE" .$uniquid, 1800, $param['mobileType']);
        }
        if($param['execute'] == 'hangup'){
            //挂断解绑
            $mobile = Lib_Redis_String::get($param['workerId']."_fl");
            if($mobile){
                Lib_Repair_Main::unBindTel([
                    'telX'=>$mobile
                ]);
            }
        }
        $res = call_user_func(array('Module_CallCenter_Main', 'request'), $param);
        if($param['execute'] == 'callOut'){
            Func_Log::write('call_socket','MESSAGE '," WORKERID：{$param['workerId']} FD：{$frame->fd} CALLTYPE：{$param['execute']} MODEL：{$param['execute']} OUTSHOW: {$param['OutShow']} PUSH_DATA:".json_encode($res));
        }else{
            Func_Log::write('call_socket','MESSAGE '," WORKERID：{$param['workerId']} FD：{$frame->fd} CALLTYPE：{$param['execute']} MODEL：{$param['execute']} PUSH_DATA:".json_encode($res));
        }
        if(in_array($param['execute'],['setIdle','setBuys']) ){

        }
        if($res['code'] != 200){
            //必要操作不提示错误
            if(in_array($param['execute'],['setIdle','setBuys']) && $res['code'] == 301){
                $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>$param['execute'], 'result'=>200,'message'=>'success']));
            }else{
                $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>$param['execute'], 'result'=>$res['code'],'error'=>$res['message']]));
            }
        }else{
            if(!empty($param['execute']) && $param['execute'] == 'callOut'){
                if($param['mobileType'] == 1){
                    $str_time = strtotime(date('Y-m-d 23:59:59'));
                    Lib_Redis_String::incr("CALLNUM-".$param['toTel']);
                    Lib_Redis_String::expireAt("CALLNUM-".$param['toTel'],$str_time);
                }
                if(!empty($isFlashsms) && $isFlashsms == 1){
                    @Lib_FlashSMS_Main::sendSMS($param['toTel']);
                }
            }
            $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>$param['execute'], 'result'=>$res['code'],'message'=>$res['message']]));
        }
    }catch (Error $err) {//捕获异常
        Func_Log::write('call_socket','MESSAGE CATCH ERROR'," WORKERID：{$param['workerId']} FD：{$frame->fd} CALLTYPE：{$param['execute']} MODEL：{$param['execute']} ERROR：".json_encode($err));
        $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>'callIn','result'=>500,'error'=>'服务器异常']));
        return false;
    }catch (Exception $e) {//捕获异常
        Func_Log::write('call_socket','MESSAGE CATCH ERROR'," WORKERID：{$param['workerId']} FD：{$frame->fd} CALLTYPE：{$param['execute']} MODEL：{$param['execute']} ERROR：".json_encode($e));
        $server->push($frame->fd, json_encode(['callType'=>$callType,'execute'=>'callIn','result'=>500,'error'=>'服务器异常']));
        return false;
    }
    return true;

});
$server->on('close', function ($ser, $fd) {
    echo $fd . '断开连接' . PHP_EOL;//输出到终端终端
});
$server->start();


